<?php

if (!function_exists('env')) {
    function env($key, $default = null, $delimiter = '.')
    {
        static $env = [];
        if (empty($env)) {
            $envFilePath = __DIR__ . '/.env';
            if (file_exists($envFilePath)) {
                $lines = parse_ini_file($envFilePath, true) ?: [];
                if (!empty($lines)) {
                    $env = $lines;
                }
            }
        }
        $keys = explode($delimiter, strtoupper($key));
        $section = null;
        if (count($keys) > 1) {
            $value = !empty($env[$keys[0]][$keys[1]]) ? $env[$keys[0]][$keys[1]] : null;
        } else {
            $value = !empty($env[$keys[0]]) ? $env[$keys[0]] : null;
        }
        if ($value !== null) {
            if (strtolower($value) === 'true') {
                return true;
            } elseif (strtolower($value) === 'false') {
                return false;
            } elseif (is_numeric($value)) {
                return intval($value);
            }
            return $value;
        } else {
            $envVar = getenv(strtoupper($key));
            if ($envVar !== false) {
                if (strtolower($envVar) === 'true') {
                    return true;
                } elseif (strtolower($envVar) === 'false') {
                    return false;
                } elseif (is_numeric($envVar)) {
                    return intval($envVar);
                }
                return $envVar;
            }
            return $default;
        }
    }
}

if (!function_exists('cpr_nl')) {
    function cpr_nl($lat)
    {
        if ($lat < 0) $lat = -$lat;
        if ($lat < 10.47047130) return 59;
        if ($lat < 14.82817437) return 58;
        if ($lat < 18.18626357) return 57;
        if ($lat < 21.02939493) return 56;
        if ($lat < 23.54504487) return 55;
        if ($lat < 25.82924707) return 54;
        if ($lat < 27.93898710) return 53;
        if ($lat < 29.91135686) return 52;
        if ($lat < 31.77209708) return 51;
        if ($lat < 33.53993436) return 50;
        if ($lat < 35.22899598) return 49;
        if ($lat < 36.85025108) return 48;
        if ($lat < 38.41241892) return 47;
        if ($lat < 39.92256684) return 46;
        if ($lat < 41.38651832) return 45;
        if ($lat < 42.80914012) return 44;
        if ($lat < 44.19454951) return 43;
        if ($lat < 45.54626723) return 42;
        if ($lat < 46.86733252) return 41;
        if ($lat < 48.16039128) return 40;
        if ($lat < 49.42776439) return 39;
        if ($lat < 50.67150166) return 38;
        if ($lat < 51.89342469) return 37;
        if ($lat < 53.09516153) return 36;
        if ($lat < 54.27817472) return 35;
        if ($lat < 55.44378444) return 34;
        if ($lat < 56.59318756) return 33;
        if ($lat < 57.72747354) return 32;
        if ($lat < 58.84763776) return 31;
        if ($lat < 59.95459277) return 30;
        if ($lat < 61.04917774) return 29;
        if ($lat < 62.13216659) return 28;
        if ($lat < 63.20427479) return 27;
        if ($lat < 64.26616523) return 26;
        if ($lat < 65.31845310) return 25;
        if ($lat < 66.36171008) return 24;
        if ($lat < 67.39646774) return 23;
        if ($lat < 68.42322022) return 22;
        if ($lat < 69.44242631) return 21;
        if ($lat < 70.45451075) return 20;
        if ($lat < 71.45986473) return 19;
        if ($lat < 72.45884545) return 18;
        if ($lat < 73.45177442) return 17;
        if ($lat < 74.43893416) return 16;
        if ($lat < 75.42056257) return 15;
        if ($lat < 76.39684391) return 14;
        if ($lat < 77.36789461) return 13;
        if ($lat < 78.33374083) return 12;
        if ($lat < 79.29428225) return 11;
        if ($lat < 80.24923213) return 10;
        if ($lat < 81.19801349) return 9;
        if ($lat < 82.13956981) return 8;
        if ($lat < 83.07199445) return 7;
        if ($lat < 83.99173563) return 6;
        if ($lat < 84.89166191) return 5;
        if ($lat < 85.75541621) return 4;
        if ($lat < 86.53536998) return 3;
        if ($lat < 87.00000000) return 2;
        else return 1;
    }
}

if (!function_exists('config_path')) {
    function config_path()
    {
        return __DIR__ . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR;
    }
}

if (!function_exists('speed_exchange')) {
    //速度节转换为千米/时
    function speed_exchange($knots)
    {
        return round($knots * 1.852, 2);
    }
}

if (!function_exists('extractRouteStr')) {
    function extractRouteStr($str)
    {
        $arr = [];
        $new_arr = explode(';', $str);
        foreach ($new_arr as $value) {
            $arr[] = explode(',', $value);
        }
        return $arr;
    }
}
if (!function_exists('python_mod')) {
    function python_mod($a, $b)
    {
        return $a - $b * floor($a / $b);
    }
}

if (!function_exists('businessLog')) {

    function businessLog($msg = "")
    {
        $date = date('Ymd'); // 获取当前日期作为文件名
        $logDir = __DIR__ . DIRECTORY_SEPARATOR . 'logs'; // 日志目录
        // 确保日志目录存在
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }
        $logFile = $logDir . DIRECTORY_SEPARATOR . "adsb_{$date}.log";
        $date_time = getPreciseTime(); // 获取精确时间
        // 写入日志
        file_put_contents($logFile, $date_time . "-" . $msg . PHP_EOL, FILE_APPEND);
    }
}
if (!function_exists('formatBytes')) {
    function formatBytes($bytes, $precision = 3)
    {
        $units = array('B', 'KB', 'MB', 'GB', 'TB');
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        $bytes /= pow(1024, $pow);
        return round($bytes, $precision);
    }
}

if (!function_exists('wgs84ToCgcs2000')) {
    /**
     * 将WGS84坐标转换为CGCS2000坐标
     *
     * @param float $longitude WGS84经度(度)
     * @param float $latitude WGS84纬度(度)
     * @param float $height WGS84高度(米)，可选，默认为0
     * @return array 包含CGCS2000坐标的数组：['longitude' => ..., 'latitude' => ..., 'height' => ...]
     */
    function wgs84ToCgcs2000($longitude, $latitude, $height = 0)
    {
        // WGS84和CGCS2000之间的转换参数(三参数模型)
        // 注意：实际上这两个坐标系非常接近，以下参数仅为示例，实际应用中可能需要更精确的参数
        $dx = 0.0;  // X轴平移(米)
        $dy = 0.0;  // Y轴平移(米)
        $dz = 0.0;  // Z轴平移(米)

        $longitude = floatval($longitude);
        $latitude = floatval($latitude);
        // 将角度转换为弧度
        $lon_rad = deg2rad($longitude);
        $lat_rad = deg2rad($latitude);

        // WGS84参考椭球体参数
        $a = 6378137.0;          // 长半轴(米)
        $f = 1 / 298.257223563;   // 扁率

        // 计算辅助值
        $e_squared = 2 * $f - $f * $f;  // 第一偏心率的平方
        $N = $a / sqrt(1 - $e_squared * sin($lat_rad) * sin($lat_rad));  // 卯酉圈曲率半径

        // 将经纬度高度转换为ECEF直角坐标(X,Y,Z)
        $X = ($N + $height) * cos($lat_rad) * cos($lon_rad);
        $Y = ($N + $height) * cos($lat_rad) * sin($lon_rad);
        $Z = ($N * (1 - $e_squared) + $height) * sin($lat_rad);

        // 应用三参数转换
        $X_cgcs = $X + $dx;
        $Y_cgcs = $Y + $dy;
        $Z_cgcs = $Z + $dz;

        // 将ECEF直角坐标转换回经纬度高度
        $p = sqrt($X_cgcs * $X_cgcs + $Y_cgcs * $Y_cgcs);
        $theta = atan2($Z_cgcs * $a, $p * sqrt($a * $a - $e_squared * $a * $a));

        // 计算CGCS2000纬度(弧度)
        $lat_rad_cgcs = atan2(
            $Z_cgcs + $e_squared * $a * $a / sqrt($a * $a - $e_squared * $a * $a) * sin($theta) * sin($theta) * sin($theta),
            $p - $e_squared * $a * cos($theta) * cos($theta) * cos($theta)
        );

        // 计算CGCS2000经度(弧度)
        $lon_rad_cgcs = atan2($Y_cgcs, $X_cgcs);

        // 计算卯酉圈曲率半径(用于高度计算)
        $N_cgcs = $a / sqrt(1 - $e_squared * sin($lat_rad_cgcs) * sin($lat_rad_cgcs));

        // 计算CGCS2000高度(米)
        $height_cgcs = $p / cos($lat_rad_cgcs) - $N_cgcs;
//            bcsub(bcdiv($p, cos($lat_rad_cgcs),8),$N_cgcs);

        // 将弧度转换回角度
        $longitude_cgcs = rad2deg($lon_rad_cgcs);
        $latitude_cgcs = rad2deg($lat_rad_cgcs);

        return [
            'lon' => $longitude_cgcs,
            'lat' => $latitude_cgcs,
            'altitude_meters' => round($height_cgcs, 2)
        ];
    }
}

if(!function_exists('getPreciseTime')){
    function getPreciseTime() {
        $timestamp = microtime(true);
        $seconds = (int)$timestamp;
        $microseconds = str_pad(round(($timestamp - $seconds) * 1000000), 6, '0', STR_PAD_LEFT);
        return date("Y-m-d H:i:s", $seconds) . ":{$microseconds}";
    }
}
